<template>
  <div style="margin: 5px; margin-top: 10px; width: 100%" ref="imageCpn">
    <div style="display:flex; justify-content:space-between; align-items:center; height:30px;">
      <label style="margin:0;">检验结果图示：</label>
      <!-- <el-input v-model="inputHeight" placeholder="请输入图片高度" @change="updateHeight"> </el-input> -->
      <MkInput class="input-height" label="图片高度" v-model="inputHeight" placeholder="请输入图片高度" @change="updateHeight"
        labelWidth="90px" isEdit />
    </div>
    <div v-if="imageList.length > 0" class="image-container">
      <div v-for="(item, ind) in imageListFmt" :key="ind" class="image-item" :style="{ height: imageItemHeight }"
        ref="imageEl" @click="handleClick">
        <img style="height: 100%" :src="item.filePath" :id="item.id || `ind${ind}`" />
      </div>
    </div>
    <div v-else>
      <div style="text-align:center; padding:5px 0; color:grey;">暂无检验结果图片</div>
    </div>
    <ImageView :imageElements="imageElements" ref="imageView" @deletePic="deletePic" showDelete />
  </div>
</template>
<script lang="ts" setup>
import ImageView from './ImageView.vue'
import { isNull } from '/@/utils/';
const props = defineProps({
  // 图片数组对象，对象应包含 id 和 filePath(图片src地址或base64编码字符串)
  imageList: {
    type: Array<any>,
    default: () => [],
  },
  // 图片删除方法由外部传入，内部主动调用
  deletePicFunc: {
    type: Function,
    default: () => { },
  },
  // 是否开启按图片内容去重
  disDuplicate: {
    type: Boolean,
    default: false
  }
})

let inputHeight = ref('500'); // 输入框内容
let imageItemHeight = ref('500px'); // 图片高度
let imageListFmt = ref<any[]>([]); // 补全base64编码前缀的图片List
let imageElements = ref<any[]>([]); // 图片节点 ，传给预览子组件
let minHeight = ref(50); // 限制图片显示的最小高度

const imageViewRef = useTemplateRef('imageView');
const deletePic = (id: any) => {
  // props.deletePicFunc(id, imageViewRef.value?.handleClose);
}
const imageElRef = useTemplateRef('imageEl');
/**
 * 初始化图片节点数组， 传递给图片预览子组件
 *
 * */
const initImageElements = () => {
  setTimeout(() => {
    if (imageElRef == null) return;
    const imageEls = imageElRef.value?.map(element => element.childNodes[0]);
    // 去重
    let m = new Map()
    imageElements.value = props.disDuplicate ? imageEls?.reduce((arr: any, curr: any) => {
      if (!m.has(curr.src) && m.set(curr.src, '')) {
        arr.push(curr);
      }
      return arr;
    }, []) as any[] : imageEls as any[];
  }, 100);
}
/**
 * 对传入的图片List去重，如果base64编码的字符串缺乏前缀'data:image/jpg;base64,'则补上
 *
 * */
const imageFmt = () => {
  imageListFmt.value = []
  // 补前缀'data:image/jpg;base64,'
  const fmtArray = props.imageList.reduce((arr: Array<any>, curr: any) => {
    arr.push({
      id: curr.id,
      filePath: base64Fmt(curr.filePath),
    })
    return arr;
  }, []);

  // 去重函数
  const filterArrayObject = function (arr: Array<any>) {
    let m = new Map();
    return arr.filter(element => !m.has(element.filePath) && m.set(element.filePath, ''));
  }

  imageListFmt.value = props.disDuplicate ? filterArrayObject(fmtArray) : fmtArray;
}
/**
 * 对传入的字符串进行正则匹配，如果为缺乏前缀的base64编码字符串，则补足并返回，其余情况直接返回
 *
 * @param {String} str 图片地址字符，网络地址或者base64编码
 * @return {String} 匹配检查后修改的字符串或是原字符串
 *
 * */
const base64Fmt = (str: string) => {
  const base64Reg = /^[A-Za-z0-9+/]*={0,2}$/;
  if (!base64Reg.test(str)) return str;
  return 'data:image/jpg;base64,' + str;
}

/**
 * 更新图片高度， 检查一组图片中的最大宽高比，保证一组图片中所有图片能完全显示，不发生溢出；
 *
 * eg：
 * 一组图片 [{width: 100, height: 200}, {width: 400, height: 50}]，
 * 设置最大高度maxHeight，如果输入高于200设置高度时会发生图片宽度溢出， 则输入300， 400， 最终都会变成200以防止图片宽度溢出，导致图片无法完全显示
 * 同样设置了最小高度minHeight， 最小高度默认50; 当最大高度maxHeight小于50时， 最小高度改为 0
 *
 * */
const imageCpnRef = useTemplateRef('imageCpn');
const updateHeight = () => {
  // 输入框内的数字为空，或者不是数字时，使用默认值
  if (isNull(inputHeight) || !(/^\d+$/.test(inputHeight.value))) {
    inputHeight.value = localStorage.getItem('InpImageItemHeight') || '500';
  }
  const newInputHeight = parseInt(inputHeight.value);
  if (isNull(imageElRef)) return [];
  // 一组图片中最大宽高比
  const maxRadio = imageElRef.value?.reduce((arr, curr) => Math.max(arr, curr.clientWidth / curr.clientHeight), 0) || 0;
  const containerWidth = imageCpnRef.value?.clientWidth || 0;
  // 最大宽高比对应的最大高度
  const maxHeight = (containerWidth - 10) / maxRadio;
  // 最小高度
  const newMinHeight = minHeight.value < maxHeight ? minHeight.value : 0;
  const height = Math.max(newMinHeight, Math.min(newInputHeight, maxHeight)).toFixed(0);
  inputHeight.value = height;
  imageItemHeight.value = `${inputHeight.value}px`;
  // 保存到本地
  localStorage.setItem('InpImageItemHeight', inputHeight.value);
}
/**
 * 对图片list进行检查 为空或者数组对象{key, value}key不符合或value为空 返回false， 否则true
 *
 * @param {[{}]} list
 * @return {Boolean}检查结果
 *
 * */
const imageListCheck = (list: Array<any>) => {
  // 判空
  if (!list || list.length === 0) return false;
  // 字段key和value检查
  list.forEach(item => {
    if (!isNull(item.id) || isNull(!item.filePath)) return false;
  })
  return true
}
/**
 * 点击图片时触发，点击事件传递给图片预览子组件
 *
 * @param {{}} e 点击事件
 *
 * */
const handleClick = (e: any) => {
  imageViewRef.value?.handleView(e);
}

watch(props.imageList, (newVal) => {
  if (newVal && newVal.length !== 0 && imageListCheck(newVal)) {
    updateHeight();
    imageFmt();
    initImageElements();
  }
}, {
  deep: true,
  immediate: true
})

/**
 * 挂载时初始化， 获取本地存储的图片高度
 *
 * */
onMounted(() => {
  imageFmt();
  updateHeight();
  inputHeight.value = localStorage.getItem('InpImageItemHeight') || '500';
})
</script>

<style scoped>
.input-height {
  position: absolute;
  top: 10px;
  right: 5px;
}

.image-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: start;
  padding: 5px 0;
  /* background-color: rgb(233, 233, 233);  */
}

.image-item {
  margin: 5px;
  background-color: #fff;
}
</style>